﻿using System;

namespace InDepth2Demo.Chapter4
{
    internal class NullableDemo
    {
        // Learning hard
        static void Call()
        {
            int? nullable = null;
            int? nullhasvalue = 1;

            // 所以下面这行代码等价于“x=nullable.HasValue?b.Value:12;”
            int x = nullable ?? 12;

            string y = "123";

            bool hasValue = nullable.HasValue;

        }

        // 可空类型装箱和拆箱的演示
        public static void BoxedandUnboxed()
        {
            // 定义一个可空类型对象nullable
            Nullable<int> nullable = 5;
            int? nullablewithoutvalue = null;

            // 获得可空对象的类型，此时返回的将是System.Int32，而不是System.Nullable<System.Int32>，// 这一点大家要特别注意

            Console.WriteLine("获取不为null的可空类型的类型为：{0}", nullable.GetType());

            // 对一个为null的类型调用方法时将出现异常，所以一般对引用类型调用方法前，最好先检测下它是否 // 为null，这是个好习惯

            //Console.WriteLine("获取为null的可空类型的类型为：{0}", nullablewithoutvalue.GetType());

            // 将可空类型对象赋给引用类型obj，此时会发生装箱操作，这可通过IL中的boxed 来证明
            object obj = nullable;

            // 获得装箱后引用类型的类型，此时输出的仍然是System.Int32，而不是System.Nullable<System.Int32>
            Console.WriteLine("获得装箱后obj 的类型：{0}", obj.GetType());

            // 拆箱后变成非可空变量
            int value = (int)obj;
            Console.WriteLine("拆箱成非可空变量的情况为：{0}", value);

            // 拆箱后变成可空变量
            nullable = (int?)obj;
            Console.WriteLine("拆箱成可空变量的情况为：{0}", nullable);

            // 对一个没有值的可空类型的对象进行装箱操作
            obj = nullablewithoutvalue;
            Console.WriteLine("对null的可空类型装箱后obj 是否为null：{0}", obj == null);

            // 拆箱成非可空变量，此时会抛出NullReferenceException异常，因为没有值的可空类型装箱后obj // 于null，引用了一个空地址
            // 相当于拆箱后把null值赋给一个int 类型的变量，此时会出现错误
            //value = (int)obj;
            //Console.WriteLine("一个没有值的可空类型装箱后，拆箱成非可空变量的情况为：{0}", value);

            // 拆箱成可空变量
            nullable = (int?)obj;
            Console.WriteLine("一个没有值的可空类型装箱后，拆箱成可空变量是否为null：{0}", nullable == null);

        }
    }
}
